package util

import (
	"io/ioutil"
	"sort"
	"strings"
	"sync"
)

func Scan(filePath string, r int, taskChan chan *FpTreeTask, wg1 *sync.WaitGroup, result *ResultTreeNode) {
	data, _ := ioutil.ReadFile(filePath)

	// 数据分块多线程扫描
	var wg = sync.WaitGroup{}
	var blockSize = len(data)/12 + 1
	var itemsCh = make(chan map[string]int, 12)
	var dataArrChan = make(chan [][]string, 12)
	for i := 0; i < len(data); i += blockSize {
		wg.Add(1)
		go _scan(i, i+blockSize, data, itemsCh, dataArrChan, &wg)
	}
	wg.Wait()

	close(itemsCh)
	close(dataArrChan)

	var items = make(map[string]int)       //所有条目和对数量的映射
	var dataArr = make([]ArInfo, 0, 30000) //所有数据
	for mp := range itemsCh {
		for key, val := range mp {
			items[key] += val
		}
	}

	var fpTree = FpTree{}
	var header = make([]string, 0, 1<<12)
	var headerMp = make(map[string]*treeNode)

	for key, val := range items {
		if val >= r {
			header = append(header, key)
			headerMp[key] = nil

		} else {
			delete(items, key)
		}
	}

	sort.Slice(header, func(i, j int) bool {
		a := items[header[i]]
		b := items[header[j]]
		if a == b {
			return header[i] > header[j]
		}
		return a > b
	})

	var mutex = &sync.Mutex{}
	var arMp = make(map[string]int)
	for ii := 0; ii < 12; ii++ {
		wg.Add(1)
		go func() {
			for arr := range dataArrChan {
				for _, v := range arr {
					var flag = false
					var tem = make([]string, 0, 16)
					for _, v1 := range v {
						if _, ok := items[v1]; ok {
							flag = true
							tem = append(tem, v1)
						}
					}
					if flag {
						s := ToString(tem)
						sort.Slice(tem, func(i, j int) bool {
							a := items[tem[i]]
							b := items[tem[j]]
							if a == b {
								return tem[i] > tem[j]
							}
							return a > b
						})

						mutex.Lock()
						if ind, ok := arMp[s]; ok {
							dataArr[ind].Count++
						} else {
							dataArr = append(dataArr, ArInfo{Arr: tem, Count: 1})
							arMp[s] = len(dataArr) - 1
						}
						mutex.Unlock()

					}
				}
			}
			wg.Done()
		}()
	}

	wg.Wait()

	fpTree.Root = &treeNode{
		val:      "",
		count:    0,
		parent:   nil,
		children: map[string]*treeNode{},
		brother:  nil,
	}
	var lastNode = fpTree.Root
	var l int
	var tNode *treeNode
	for _, v := range dataArr {
		lastNode = fpTree.Root
		l = len(v.Arr)
		for i := 0; i < l; i++ {
			if v1, ok := lastNode.children[v.Arr[i]]; !ok {
				for ; i < l; i++ {
					v2 := headerMp[v.Arr[i]]
					tNode = &treeNode{
						count:    v.Count,
						val:      v.Arr[i],
						parent:   lastNode,
						children: map[string]*treeNode{},
						brother:  v2}
					lastNode.children[v.Arr[i]] = tNode
					headerMp[v.Arr[i]] = tNode
					lastNode = tNode
				}
			} else {
				v1.count += v.Count
				lastNode = v1
			}
		}
	}

	result.Next = make([]*ResultTreeNode, len(header))

	var c = make(chan int, len(header))
	for i := 0; i < len(header); i++ {
		c <- i
	}
	close(c)

	for i := 0; i < 12; i++ {
		wg.Add(1)
		go func() {
			for l := range c {
				result.Next[l] = &ResultTreeNode{
					Val:   header[l],
					Count: items[header[l]],
				}
				var task = FpTreeTask{
					resTree: result.Next[l],
					ArrData: make([]*ArInfo, 0, 64),
				}
				for now := headerMp[header[l]]; now != nil; now = now.brother {
					var arrIn = &ArInfo{
						Arr:   make([]string, 0, 16),
						Count: now.count,
					}
					for now1 := now.parent; now1.count != 0; now1 = now1.parent {
						arrIn.Arr = append(arrIn.Arr, now1.val)
					}
					if len(arrIn.Arr) != 0 {
						task.ArrData = append(task.ArrData, arrIn)
					}

				}
				if len(task.ArrData) != 0 {
					wg1.Add(1)
					taskChan <- &task

				}

			}
			wg.Done()
		}()
	}
	wg.Wait()
}

func _scan(begin, end int, data []byte, itemsCh chan map[string]int, dataArrChan chan [][]string, wg *sync.WaitGroup) {
	var mp = make(map[string]int, 2000)
	//将指针退至行首
	for begin >= 0 && data[begin] != 10 {
		begin--
	}
	begin++

	//end 退回至行首
	if end > len(data) {
		end = len(data)
	} else {
		for end >= 0 && data[end] != 10 {
			end--
		}
		end++
	}
	var l = begin
	itemArr := make([][]string, 0, 10000)
	tem := make([]string, 0, 100)
	var arr = &tem
	for i := begin; i < end; i++ {
		if data[i] == ' ' {
			var tem = string(data[l:i])
			*arr = append(*arr, tem)
			mp[tem] += 1
			l = i + 1
		} else {
			if data[i] == '\n' {
				l++
				itemArr = append(itemArr, *arr)
				t := make([]string, 0, 100)
				arr = &t
				continue
			}
		}
	}
	itemsCh <- mp
	dataArrChan <- itemArr
	wg.Done()

}

func ToString(ar []string) string {
	var sb = strings.Builder{}
	for _, s := range ar {
		sb.WriteString(s)
		sb.WriteByte('|')
	}
	return sb.String()

}

func Serve(r int, taskChan chan *FpTreeTask, wg *sync.WaitGroup) {
	for t := range taskChan {
		var mp = make(map[string]int)
		for _, v := range t.ArrData {
			for _, v2 := range v.Arr {
				mp[v2] += v.Count
			}
		}
		var header = make([]string, 0, 64)
		var headerMap = make(map[string]*treeNode)
		for k, v := range mp {
			if v >= r {
				header = append(header, k)
			} else {
				delete(mp, k)
			}
		}
		sort.Slice(header, func(i, j int) bool {
			a := mp[header[i]]
			b := mp[header[j]]
			if a == b {
				return header[i] > header[j]
			}
			return a > b
		})
		var ard = make([]*ArInfo, 0, 128)
		var mpS = make(map[string]int)
		for _, v := range t.ArrData {
			var arIn = &ArInfo{}
			for _, v2 := range v.Arr {
				if _, ok := mp[v2]; ok {
					arIn.Arr = append(arIn.Arr, v2)
				}
			}
			if len(arIn.Arr) > 0 {
				sTem := ToString(arIn.Arr)
				if ind, ok := mpS[sTem]; ok {
					ard[ind].Count += v.Count
				} else {
					sort.Slice(arIn.Arr, func(i, j int) bool {
						a := mp[arIn.Arr[i]]
						b := mp[arIn.Arr[j]]
						if a == b {
							return arIn.Arr[i] > arIn.Arr[j]
						}
						return a > b
					})
					arIn.Count = v.Count
					ard = append(ard, arIn)
					mpS[sTem] = len(ard) - 1
				}
			}
		}
		var fpTree = FpTree{}
		fpTree.Root = &treeNode{
			val:      "",
			count:    0,
			parent:   nil,
			children: map[string]*treeNode{},
			brother:  nil,
		}
		var lastNode *treeNode
		for _, v := range ard {
			lastNode = fpTree.Root
			for i := 0; i < len(v.Arr); i++ {
				if v2, ok := lastNode.children[v.Arr[i]]; ok {
					v2.count += v.Count
					lastNode = v2
				} else {
					for ; i < len(v.Arr); i++ {
						v1 := headerMap[v.Arr[i]]
						tNode := &treeNode{
							val:      v.Arr[i],
							count:    v.Count,
							parent:   lastNode,
							children: map[string]*treeNode{},
							brother:  v1,
						}
						lastNode.children[v.Arr[i]] = tNode
						headerMap[v.Arr[i]] = tNode
						lastNode = tNode
					}
				}
			}
		}
		if fpTree.IsFinal() {
			var tn = &ResultTreeNode{
				Val:     "",
				IsFinal: true,
				Next:    nil,
			}
			tn.End, tn.EndCount = fpTree.getL()
			t.resTree.Next = []*ResultTreeNode{tn}
		} else {
			t.resTree.Next = make([]*ResultTreeNode, len(header))
			for l := len(header) - 1; l >= 0; l-- {
				tn := &ResultTreeNode{
					Val:   header[l],
					Count: mp[header[l]],
				}
				t.resTree.Next[l] = tn
				var task = FpTreeTask{
					resTree: tn,
					ArrData: make([]*ArInfo, 0, 64),
				}

				for now := headerMap[header[l]]; now != nil; now = now.brother {
					var arrIn = &ArInfo{
						Arr:   make([]string, 0, 8),
						Count: now.count,
					}
					for now1 := now.parent; now1.count != 0; now1 = now1.parent {
						arrIn.Arr = append(arrIn.Arr, now1.val)
					}
					if len(arrIn.Arr) != 0 {
						task.ArrData = append(task.ArrData, arrIn)
					}

				}
				if len(task.ArrData) != 0 {
					wg.Add(1)
					taskChan <- &task

				}

			}
		}
		wg.Done()
	}

}
